<?php
if (! defined ( 'BASEPATH' ))
	exit ( 'No direct script access allowed' );

/**
 * 受控文件api
 * @author Skiychan <dev@skiy.net>
 */

/**
	@param:  file_id: 	表示文件u_file的guid
	@param: _rsvd_ts:	表示当前客户端的时间

	【策略URL】
	获取策略：		http://www.unclone.cn/api/policys/get_all
	通知服务器打开：http://www.unclone.cn/api/policys/open
	通知服务器关闭：http://www.unclone.cn/api/policys/close
 */

class Policys extends CI_Controller {

	public function __construct() {
		parent::__construct ();
		$this->load->library('common');
        $this->load->library('traces');
        $this->load->service('user_files_service');
        $this->load->service('user_policies_service');
		$this->load->service('login_service');

	}

	/**
	 * 打开受控文件
	旧版策略JSON
	{
	"ret": -1,
	"cipher": "xxx",
	property: {
		"delete": "1"
	},
	"policy": [{
			"id": 1,
			"value_set": "xxx",
			"value": "xxx"
		},
		{
			"id": 2,
			"value_set": "xxx",
			"value": "xxx"
		},
		{
			"id": 4
		},
		{
			"id": 5,
			"value_set": "xxx"
		}]
	}
		字段         类型     说明
		ret          整数     -1表示正常,10表示文件已删除
		cipher       字符串   文档解密密钥
		delete	     字符串   存在则自毁
		policy       数组     该数组下存放所有策略
		id           整数
		1：表示查阅次数，value_set表示能够阅读的最大次数，value表示已经阅读的次数
		2：表示查阅时间，value_set表示到期时间，value表示服务器当前时间
		4：表示禁止访问，value_set和value被忽略
		5：表示查阅密码，value_set表示查阅密码，value被忽略
	 */
	/**
	 * 获取所有安全策略
	 * @return mixed
	 */
	public function get_all() {
		$file_guid = trim($this->input->get_post('file_id', true));
		$ts = (int)$this->input->get_post('_rsvd_ts', true);

		#文件guid
		if (empty($file_guid)) {
			$json = Common::prf_json (FALSE, NULL, NULL, $ts, FALSE);
			return $this->common->rc4_json($json);
		}
		#时间
		if ($ts <= 0) {
			$json = Common::prf_json(FALSE, NULL, NULL, $ts, FALSE);
			return $this->common->rc4_json($json);
		}

		#取得文件信息(策略、密钥等)
		$file_fields="id,name,size,creation_ts,modify_ts,access_denied,description,deleted,type";
		$file = $this->user_files_service->get_all_file_info_by_guid($file_guid, '', '', '', $file_fields, 'data', 'cipher');

		#文件不存在或权限失效
		$pri = array("ret" => 10, "_rsvd_ts" => $ts);
		if (empty($file) || $file['deleted'] == 1)
            return $this->common->rc4_json(json_encode($pri));

		#禁止访问
		if ($file['access_denied'] == 1) {
			$pri['policy'][] = array("id" => 4);
			$pri['ret'] = -1;
			return $this->common->rc4_json(json_encode($pri));
		}

		$paramArr = array(
			"cipher" => $file['cipher'],
			"_rsvd_ts" => $ts
		);

        #取得基本策略描述
		# 1.open_counter, 2.life_span, 3.delete_after_expired, 4.access_denied, 5.read_pwd
        $policies = $this->user_policies_service->get_base_policies();
       	#unset($policies['access_denied']['catagory'], $policies['access_denied']['description']);
		#unset($policies[4]['description'], $policies[4]['catagory']);

		$pri = array (
				"ret" => -1
		) + $paramArr;

		#进程指纹
        $this->load->library("digest");
        $app_digests = Digest::get_digest(1);
		//$app_digests = $this->db->get_where("app_digest",array("file_type_id" => $file['type']))->result_array();
		if (count($app_digests) > 0){
			$valid_app = array();
			foreach ($app_digests as $key => $app_digest) {
				$valid_app[$key]['app'] = $app_digest['description'];
				$valid_app[$key]['digest'] = $app_digest['app_digest'];
			}
			$pri['app_verification'] = array(
                'enable' => 'false',
                'valid_app' => $valid_app
            );
		}

		$file_policies = json_decode($file['data'], true);
        //如果不存在策略
		if (count($file_policies) < 1)
            return $this->common->rc4_json(json_encode($pri));

		$data = array();
		$i = 0;
		#文件策略
		foreach ($file_policies as  $index => $file_policy){
			#基础策略
			foreach ($policies as  $py_index => $policy){
                //策略相同
				if ($file_policy['des'] == $policy['description']) {

					#idx=3,阅后即焚
					if ($policy['catagory'] == 2 ) {
						if($file_policy['value_set'] == '1'){
							$pri['property']['delete'] = "1";
						}
						break;
					}

                    //空值
					if (empty($file_policy['value_set'])) break;

					$data[$i]['id'] = $py_index;//$policy['id'];
					$data[$i]['priority'] = (string)$policy['priority'];
					$data[$i]['phase'] = (string)$policy['phase'];

                    #可查阅时间
					if ($policy['description'] == "life_span") {
						$data[$i]['value_set'] = (string)$file_policy['value_set'];
						$data[$i]['value'] = (string)time();
						$i++;
						break;
					}

                    #查询密码
					if($policy['description'] == "read_pwd") {
						#查询密码MD5
						$file_policy['value_set'] = empty($file_policy['value_set']) ? '' : md5($file_policy['value_set'].'WOWOSTAR');
					}

					$data[$i]['value_set'] = (string)$file_policy['value_set'];

					if (! isset($file_policy['value']))
						$file_policy['value'] = "0";

					$data[$i]['value'] = (string)$file_policy['value'];
					$i++;
				}
			}
		}

        #如果有值
		if (count($data) > 0)
			$pri['policy'] = $data;

		return $this->common->rc4_json(json_encode($pri));
	}

	/**
	 * 新版策略JSON
	 * @return mixed
	{
		"ret": -1,
		"version": "1.1",
		"cipher": "xxx",
		"password": "xxx",
		"denyAccess": 0,
		"selfDestroy": 1,
		"timeLimit": {
		"currentTime": 1111111,
		"expireTime": 2222222
	},
	"countLimit": {
		"readCount": 0,
		"maxCount": 1
		}
	}
	字段         类型     说明
	ret          整数     -1表示正常,10表示文件已删除
	version      字符串   版本,目前取值为1.1
	cipher       字符串   文档解密密钥
	password     字符串   查阅密码
	denyAccess   整数     取值为非0表示禁止查阅
	selfDestroy  整数     取值为非0表示自毁,结合timeLimit或countLimit才有意义
	timeLimit    对象     时间限制
	currentTime 整数     服务器当前时间
	expireTime  整数     到期时间
	countLimit   对象     次数限制
	readCount   整数     已经阅读的次数
	maxCount    整数     能够阅读的最大次数
	 */
	/**
	 * 获取安全策略,新版,
	 */
	public function get_policy() {
		$file_guid = trim($this->input->get_post('file_id', true));
		$ts = (int)$this->input->get_post('_rsvd_ts', true);

		#文件guid
		if (empty($file_guid)) {
			$json = Common::prf_json (FALSE, NULL, NULL, $ts, FALSE);
			return $this->common->rc4_json($json);
		}
		#时间
		if ($ts <= 0) {
			$json = Common::prf_json(FALSE, NULL, NULL, $ts, FALSE);
			return $this->common->rc4_json($json);
		}

		#取得文件信息(策略、密钥等)
		$file_fields="id,name,size,creation_ts,modify_ts,access_denied,description,deleted,type";
		$file = $this->user_files_service->get_all_file_info_by_guid($file_guid, '', '', '', $file_fields, 'data', 'cipher');

		#文件不存在或权限失效
		$pri = array("ret" => 10, "_rsvd_ts" => $ts);
		if (empty($file) || $file['deleted'] == 1 || empty($file['cipher']))
			return $this->common->rc4_json(json_encode($pri));

		#文件策略初始
		$file_policy_init = json_decode($file['data'], true);
		$new_policy = array();
		#数据库有文件策略
		foreach ($file_policy_init as $key => $value) {
			$des = $value['des'];
			unset($value['des']);
			$new_policy[$des] = $value;
		}

		$password = "";
		if (isset($new_policy['read_pwd']['value_set']) &&
			!empty($new_policy['read_pwd']['value_set'])) {
			$password 		= $new_policy['read_pwd']['value_set'];
		}

		$encryption 	= !empty($password) ? md5($password.'WOWOSTAR') : "";
		$delete_after 	= isset($new_policy['delete_after_expired']['value_set']) ? (int)$new_policy['delete_after_expired']['value_set'] : 0;
		$life_span		= isset($new_policy['life_span']['value_set']) ? (int)$new_policy['life_span']['value_set'] : -1;
		$open_counter 	= isset($new_policy['open_counter']['value_set']) ? (int)$new_policy['open_counter']['value_set'] : 0;
		$read_count		= isset($new_policy['open_counter']['value']) ? (int)$new_policy['open_counter']['value'] : 0;

		if ($life_span === 0) $life_span = -1;

		$resp = array(
			'ret'			=> -1,
			'cipher'		=> $file['cipher'],
			'password'		=> $encryption,
			'denyAccess'	=> (int)$file['access_denied'],
			'selfDestroy'	=> $delete_after,
			'timeLimit'		=> array(
				'currentTime'	=> time(),
				'expireTime'	=> $life_span,
			),
			'countLimit'	=> array(
				'readCount'		=> $read_count,
				'maxCount'		=> $open_counter
			)
		);

		return $this->common->rc4_json(json_encode($resp));
	}

	/**
	 * 打开文件
	 * @return mixed
	 */
	public function open() {
		$file_guid = trim($this->input->get_post('file_id', true));
		$ts = (int)$this->input->get_post('_rsvd_ts', true);
		/*
		$secure_type = 1;  //受控文件类型（1：exe方式，2：简单加解密方式）
		$secure_arr = array('type' => $secure_type);
		*/

		#文件guid
		if (empty($file_guid)) {
			log_message('error', "api policy open param(file_id) is null for new version" );
			$json = Common::prf_json (FALSE, NULL, NULL, $ts, FALSE);
			return $this->common->rc4_json($json);
		}
		#时间
		if ($ts <= 0) {
			log_message('error', "api policy open param(ts) is null for new version" );
			$json = Common::prf_json(FALSE, NULL, NULL, $ts, FALSE);
			return $this->common->rc4_json($json);
		}

		#取得文件信息(策略、密钥等)
		$file_fields="id,name,size,creation_ts,modify_ts,access_denied,description,deleted,type";
		$file = $this->user_files_service->get_all_file_info_by_guid($file_guid, '', '', '', $file_fields, 'data', 'cipher');

		#无文件,无密钥,受限
		if (empty($file) || empty($file['cipher']) || ($file['access_denied'] == 1))
			return $this->common->rc4_json(json_encode(array("ret" => 10,"_rsvd_ts"=>$ts)));

		$file_id = $file['id'];
		$viewer_id = 0;  //查阅者id
		$find_uid = $this->login_service->get_user_info('id');
		if (! empty($find_uid)) $viewer_id = $find_uid;
		#添加查阅轨迹
		Traces::trace_file($file_id, Traces::EVENT_OPEN_SECURE_FILE, '', '', $viewer_id);

		#文件策略初始
		$file_policy_init = json_decode($file['data'], true);

		$policy_open_counter = false;  //查阅策略
		$new_policy = array();

		#数据库有文件策略
		if (isset($file_policy_init)) {
			foreach ($file_policy_init as $key => $value) {
				#取得查阅权限
				if ($value['des'] == "open_counter") {
					$policy_open_counter = $value;
					continue;
				}
				#保存除open_counter外的值
				$new_policy[] = $value;
			}
		}

		#查阅权限
		if (empty($policy_open_counter)) {
			log_message('error', "api policy open select open_counter is null");
			$json = Common::prf_json(TRUE, NULL, NULL, $ts, FALSE);
			return $this->common->rc4_json($json);
		}
		#无限次查阅
		if ($policy_open_counter['value_set'] === 0){
			log_message('debug', "api policy open value_set no limit open acount");
			$json = Common::prf_json(TRUE, NULL, NULL, $ts, FALSE);
			return $this->common->rc4_json($json);
		}

		#之前已查阅次数
		$viewed_times = isset($policy_open_counter['value']) ? (int)$policy_open_counter['value'] : 0;
		$residue_degree = $policy_open_counter['value_set'] - $viewed_times;
		#查阅次数超出范围,不能打开文件
		if ($residue_degree < 1) {
			log_message('error', "api policy open value aready $residue_degree}, can't open it now");
			return $this->common->rc4_json(json_encode(array("ret" => 9,"_rsvd_ts"=>$ts)));
		}

		$viewed_times++;
		log_message('debug', "api policy open value aready {$viewed_times},not need set");

		$policy_open_counter['value'] = $viewed_times;
		#更新策略
		array_push($new_policy, $policy_open_counter);
		sort($new_policy);

		#更新策略查阅权限,文件将过期
		if ($residue_degree == 1) {
			$this->user_policies_service->update_policy($file_id, 1,$new_policy, array('expired' => 1));
		} else {
			$this->user_policies_service->update_policy($file_id, 1,$new_policy);
		}

		if ($this->db->affected_rows () < 1) {
			log_message('error', "api policy open update value fail");
			$json = Common::prf_json(FALSE, NULL, NULL, $ts, FALSE);
			return $this->common->rc4_json($json);
		}

		$json = Common::prf_json(TRUE, NULL, NULL, $ts, FALSE);
		return $this->common->rc4_json($json);
	}

	/**
	 * 关闭文件
	 * @param is_del: 策略里有自毁则需要带此参数，没有自毁则不需要带
	 * @return mixed
	 */
	public function close() {
		$file_guid = trim($this->input->get_post('file_id', true));
		$is_delete = (int)$this->input->get_post("is_del", true);
		$ts = (int)$this->input->get_post('_rsvd_ts', true);

		#文件guid
		if (empty($file_guid)) {
			log_message('error', "api policy close param(file_id) is null");
			$json= Common::prf_json(FALSE, NULL, NULL, $ts, FALSE);
			return $this->common->rc4_json($json);
		}
		#时间
		if ($ts <= 0) {
			log_message('error', "api policy close param(ts) is null");
			$json= Common::prf_json(FALSE, NULL, NULL, $ts, FALSE);
			return $this->common->rc4_json($json);
		}

		//取得文件信息(策略、密钥等)
		$file_fields="id,name,size,creation_ts,modify_ts,access_denied,description,deleted,type";
		$file = $this->user_files_service->get_all_file_info_by_guid($file_guid, '', '', '', $file_fields, 'data', 'cipher');

		if (empty($file) || empty($file['cipher']))
			return $this->common->rc4_json(json_encode(array("ret" => 10,"_rsvd_ts"=>$ts)));

		$file_id = $file['id'];
		$viewer_id = 0;  //查阅者id
		$find_uid = $this->login_service->get_user_info('id');
		if (! empty($find_uid)) $viewer_id = $find_uid;

		#添加关闭轨迹
		Traces::trace_file($file_id, Traces::EVENT_CLOSE_SECURE_FILE, '', '', $viewer_id);

		#是否删除
		if ($is_delete == 1)
			Traces::trace_file($file_id, Traces::EVENT_DELETE_SECURE_FILE, '', '', $viewer_id);

		$json = Common::prf_json(TRUE, NULL, NULL, $ts, FALSE);
		return $this->common->rc4_json($json);
	}

}
